﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace Dare.Utilities.Media
{
    public class FFmpegMediaInfo : IDisposable
    {
        private IntPtr pFormatContext;
        private FFmpeg.AVFormatContext formatContext;

        private Exception lastException;

        public Exception LastException
        {
            get { return lastException; }
        }

        private string formatName;
        public string FormatName
        {
            get { return formatName; }
        }

        private string formatFullName;
        public string FormatFullName
        {
            get { return formatFullName; }
        }


        private string formatExtension;
        public string FormatExtension
        {
            get { return formatExtension; }
        }


        private bool hasVideo;
        public bool HasVideo
        {
            get { return hasVideo; }
        }

        private bool hasAudio;
        public bool HasAudio
        {
            get { return hasAudio; }
        }

        private int videoWidth;
        public int VideoWidth
        {
            get { return videoWidth; }
        }

        private int videoHeight;
        public int VideoHeight
        {
            get { return videoHeight; }
        }

        private double videoFrameRate;
        public double VideoFrameRate
        {
            get { return videoFrameRate; }
        }

        private long videoFrameCount;
        public long VideoFrameCount
        {
            get { return videoFrameCount; }
        }


        private int videoBitrate;
        public int VideoBitrate
        {
            get { return videoBitrate; }
        }

        private FFmpeg.CodecID videoFormat;
        public FFmpeg.CodecID VideoFormat
        {
            get { return videoFormat; }
        }

        private int audioChannels;

        public int AudioChannels
        {
            get { return audioChannels; }
            set { audioChannels = value; }
        }

        private int audioFrequency;
        public int AudioFrequency
        {
            get { return audioFrequency; }
        }

        private int audioSampleRate;
        public int AudioSampleRate
        {
            get { return audioSampleRate; }
        }
	

        private int audioBitrate;
        public int AudioBitrate
        {
            get { return audioBitrate; }
            set { audioBitrate = value; }
        }


        private FFmpeg.CodecID audioFormat;
        public FFmpeg.CodecID AudioFormat
        {
            get { return audioFormat; }
        }

        private TimeSpan mediaDuration;
        public TimeSpan MediaDuration
        {
            get { return mediaDuration; }
        }

        public FileInfo FileInfo
        {
            get { return fileInfo; }
            set { fileInfo = value; }
        }
        private FileInfo fileInfo;

        public FFmpegMediaInfo()
        {
            
        }

        public FFmpegMediaInfo(string fileName)
            : this()
        {
            if (String.IsNullOrEmpty(fileName))
            {
                fileInfo = new FileInfo(fileName);
                Refresh();
            }
        }

        public FFmpegMediaInfo(FileInfo fileInfo)
            : this()
        {
            this.fileInfo = fileInfo;
            Refresh();
        }

        public bool Refresh()
        {
            if (FileInfo == null) return false;
            FileInfo.Refresh();
            if (!FileInfo.Exists) return false;

            //FFmpeg.av_register_all();

            int ret;
            //打开媒体文件
            ret = FFmpeg.av_open_input_file(out pFormatContext, FileInfo.FullName, IntPtr.Zero, 0, IntPtr.Zero);
            if (ret < 0)
            {
                lastException = new Exception("无法打开文件 " + FileInfo.FullName);
                return false;
            }

            try
            {
                //寻找媒体流
                ret = FFmpeg.av_find_stream_info(pFormatContext);
                if (ret < 0)
                {
                    lastException = new Exception("无法找到媒体流信息");
                    return false;
                }

                formatContext = (FFmpeg.AVFormatContext)Marshal.PtrToStructure(pFormatContext, typeof(FFmpeg.AVFormatContext));

                FFmpeg.AVInputFormat inputFormat = (FFmpeg.AVInputFormat)Marshal.PtrToStructure(formatContext.pAVInputFormat, typeof(FFmpeg.AVInputFormat));

                formatName = inputFormat.name;
                formatFullName = inputFormat.long_name;
                formatExtension = inputFormat.extensions;

                mediaDuration = TimeSpan.FromTicks(formatContext.duration * 10);
                for (int i = 0; i < formatContext.nb_streams; i++)
                {
                    FFmpeg.AVStream stream = (FFmpeg.AVStream)Marshal.PtrToStructure(formatContext.streams[i], typeof(FFmpeg.AVStream));

                    FFmpeg.AVCodecContext codec = (FFmpeg.AVCodecContext)Marshal.PtrToStructure(stream.codec, typeof(FFmpeg.AVCodecContext));


                    if (codec.codec_type == FFmpeg.CodecType.CODEC_TYPE_AUDIO)
                    {
                        hasAudio = true;
                        audioChannels = codec.channels;
                        audioFrequency = codec.sample_rate;
                        audioBitrate = codec.bit_rate;
                        switch (codec.sample_fmt)
                        {
                            case FFmpeg.SampleFormat.SAMPLE_FMT_S16:
                                audioSampleRate = 16;
                                break;
                            case FFmpeg.SampleFormat.SAMPLE_FMT_S24:
                                audioSampleRate = 24;
                                break;
                            case FFmpeg.SampleFormat.SAMPLE_FMT_S32:
                                audioSampleRate = 32;
                                break;
                            case FFmpeg.SampleFormat.SAMPLE_FMT_U8:
                                audioSampleRate = 8;
                                break;
                            default:
                                audioSampleRate = 0;
                                break;
                        }
                        audioFormat = codec.codec_id;

                        TimeSpan audioDuration = TimeSpan.FromTicks(stream.duration * 10);
                        if (audioDuration > mediaDuration) mediaDuration = audioDuration;
                    }
                    else if (codec.codec_type == FFmpeg.CodecType.CODEC_TYPE_VIDEO)
                    {
                        hasVideo = true;
                        videoWidth = codec.width;
                        videoHeight = codec.height;
                        videoFormat = codec.codec_id;
                        videoBitrate = codec.bit_rate;
                        videoFrameRate = FFmpegHelper.GetFrameRate(stream, codec);
                        videoFrameCount = (long)(videoFrameRate * mediaDuration.TotalSeconds);

                        TimeSpan videoDuration = TimeSpan.FromTicks(stream.duration * 10);
                        if (videoDuration > mediaDuration) mediaDuration = videoDuration;
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                lastException = ex;
                return false;
            }
            finally
            {
                try
                {
                    FFmpeg.av_close_input_file(pFormatContext);
                }
                catch { }
                //try
                //{
                //    FFmpeg.av_free_static();
                //}
                //catch { }
            }
        }

        public static string GetCodeFormatName(FFmpeg.CodecID codecID)
        {
            switch (codecID)
            {
                case FFmpeg.CodecID.CODEC_ID_WMV3:
                    return "WMV9 视频";
                case FFmpeg.CodecID.CODEC_ID_MPEG2VIDEO:
                    return "MPEG2 视频";
                case FFmpeg.CodecID.CODEC_ID_MPEG1VIDEO:
                    return "MPEG1 视频";
                case FFmpeg.CodecID.CODEC_ID_MPEG4:
                    return "MPEG4 视频";
                case FFmpeg.CodecID.CODEC_ID_RV40:
                    return "RealVideo4 视频";
                case FFmpeg.CodecID.CODEC_ID_RV30:
                    return "RealVideo3 视频";
                case FFmpeg.CodecID.CODEC_ID_RV20:
                    return "RealVideo2 视频";
                case FFmpeg.CodecID.CODEC_ID_RV10:
                    return "RealVideo1 视频";
                default:
                    return codecID.ToString();
            }
        }

        #region IDisposable 成员

        public void Dispose()
        {
            
        }

        #endregion
    }
}
